﻿using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace CJJ.Common.Validator
{
    internal static class Common
    {
        public static ConcurrentDictionary<PropertyInfo, bool> IsChkInnerParamAttrDic = new ConcurrentDictionary<PropertyInfo, bool>();

        /// <summary>
        /// XML序列化方式深复制
        /// </summary>
        /// <param name="obj">对象</param>
        /// <param name="type">对象类型</param>
        /// <returns>复制对象</returns>
        internal static object DeepCopy(this object obj, Type type)
        {
            object retval;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlSerializer xml = new XmlSerializer(type);
                xml.Serialize(ms, obj);
                ms.Seek(0, SeekOrigin.Begin);
                retval = xml.Deserialize(ms);
                ms.Close();
            }

            return retval;
        }

        /// <summary>
        /// 获取指定数组中每个元素的类型
        /// </summary>
        /// <param name="t">数组类型</param>
        /// <returns>元素类型</returns>
        internal static Type GetArrayElementType(this Type t)
        {
            if (!t.IsArray) return null;
            if (t.FullName != null)
            {
                string tName = t.FullName.Replace("[]", string.Empty);
                Type elType = t.Assembly.GetType(tName);
                return elType;
            }

            return null;
        }

        /// <summary>
        /// 判断类型是否需要进行递归检查
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns>判断结果，需要递归检查=true</returns>
        internal static bool IsNeedRecursionChk(this Type type)
        {
            return type.IsClass && type != typeof(string) && !type.IsCollectionType();
        }

        /// <summary>
        /// 判断是否是数字类型
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns>判断结果，数字类型=true</returns>
        internal static bool IsNumericType(this Type type)
        {
            switch (Type.GetTypeCode(type))
            {
                case TypeCode.Byte:
                case TypeCode.SByte:
                case TypeCode.UInt16:
                case TypeCode.UInt32:
                case TypeCode.UInt64:
                case TypeCode.Int16:
                case TypeCode.Int32:
                case TypeCode.Int64:
                case TypeCode.Decimal:
                case TypeCode.Double:
                case TypeCode.Single:
                    return true;
                default:
                    return false;
            }
        }

        /// <summary>
        /// 判断是否是集合类型
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns>判断结果，集合类型=true</returns>
        internal static bool IsCollectionType(this Type type)
        {
            if (type == typeof(string))
            {
                return false;
            }
            var superClassType = typeof(ICollection);
            var superClassType1 = typeof(ICollection<>);

            var flg = HasImplementedRawGeneric(type, superClassType);
            var flg1 = HasImplementedRawGeneric(type, superClassType1);

            if (flg || flg1)
            {
                return true;
            }

            //if (Array.IndexOf(type.GetInterfaces(), superClassType) > -1
            //|| type.IsSubclassOf(superClassType)
            //|| Array.IndexOf(type.GetInterfaces(), superClassType1) > -1
            //|| type.IsSubclassOf(superClassType1))
            //{
            //    return true;
            //}
            return type.IsArray;
        }

        /// <summary>
        /// 判断是否是集合类型
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns>判断结果，集合类型=true</returns>
        internal static bool IsListType(this Type type)
        {
            if (type == typeof(string) || type == typeof(ArrayList))
            {
                return false;
            }
            var superClassType = typeof(IList);
            var superClassType1 = typeof(IList<>);

            var flg = HasImplementedRawGeneric(type, superClassType);
            var flg1 = HasImplementedRawGeneric(type, superClassType1);

            if (flg || flg1)
            {
                return true;
            }

            //if (type == superClassType
            //    || type == superClassType1
            //    || Array.IndexOf(type.GetInterfaces(), superClassType) > -1
            //    || type.IsSubclassOf(superClassType)
            //    || Array.IndexOf(type.GetInterfaces(), superClassType1) > -1
            //    || type.IsSubclassOf(superClassType1))
            //{
            //    return true;
            //}
            return type.IsArray;
        }

        /// <summary>
        /// 判断整数的位数
        /// </summary>
        /// <param name="val">要判断的值</param>
        /// <returns>位数</returns>
        internal static int NumberOfIntegerDigits(this long val)
        {
            int cnt = 0;
            while (val > 0)
            {
                val /= 10;
                ++cnt;
            }
            return cnt;
        }

        /// <summary>
        /// 判断小数的位数
        /// </summary>
        /// <param name="val">要判断的值</param>
        /// <returns>位数</returns>
        internal static int NumberOfDecimalDigits(this decimal val)
        {
            int cnt = 0;
            var str = val.ToString();
            for (int i = str.Length - 1; i >= 0; i--)
            {
                if (str[i] == '0' && cnt == 0)
                {
                    continue;
                }
                if (str[i] == '.')
                {
                    return cnt;
                }
                cnt++;
            }
            return 0;
        }

        /// <summary>
        /// 判断是否应该级联检查
        /// </summary>
        /// <param name="prop">属性</param>
        /// <returns>判断结果</returns>
        internal static bool ShouldChkInnerParam(this PropertyInfo prop)
        {
            if (IsChkInnerParamAttrDic.ContainsKey(prop))
            {
                return IsChkInnerParamAttrDic[prop];
            }

            foreach (Attribute attr in prop.GetCustomAttributes(true))
            {
                if (attr.GetType() == typeof(InnerValidAttribute))
                {
                    IsChkInnerParamAttrDic.AddOrUpdate(prop, true, ((key, val) => true));
                    return true;
                }
            }
            IsChkInnerParamAttrDic.AddOrUpdate(prop, false, ((key, val) => false));
            return false;
        }

        /// <summary>
        /// 判断指定的类型 <paramref name="type"/> 是否是指定泛型类型的子类型，或实现了指定泛型接口。
        /// </summary>
        /// <param name="type">需要测试的类型。</param>
        /// <param name="generic">泛型接口类型，传入 typeof(IXxx&lt;&gt;)</param>
        /// <returns>如果是泛型接口的子类型，则返回 true，否则返回 false。</returns>
        internal static bool HasImplementedRawGeneric(this Type type, Type generic)
        {
            if (type == null) throw new ArgumentNullException(nameof(type));
            if (generic == null) throw new ArgumentNullException(nameof(generic));

            // 测试接口。
            var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType);
            if (isTheRawGenericType) return true;

            // 测试类型。
            while (type != null && type != typeof(object))
            {
                isTheRawGenericType = IsTheRawGenericType(type);
                if (isTheRawGenericType) return true;
                type = type.BaseType;
            }

            // 没有找到任何匹配的接口或类型。
            return false;

            // 测试某个类型是否是指定的原始接口。
            bool IsTheRawGenericType(Type test)
                => generic == (test.IsGenericType ? test.GetGenericTypeDefinition() : test);
        }

        public static async Task<T> ToTask<T>(T obj)
        {
            T result = (T)obj;
            return await Task.FromResult(result);
        }
    }
}
